﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace FollowWindow
{
    public class CSharpAPIs
    {
        private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam);
        [DllImport("user32.dll")]
        private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);
        //[DllImport("user32.dll")]
        //private static extern IntPtr FindWindowW(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        private static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll")]
        private static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount);


        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);


        [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndlnsertAfter, int X, int Y, int cx, int cy, uint Flags);

        [DllImport("user32.dll", EntryPoint = "SetParent")]
        public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint);


        [DllImport("user32.dll")]
        public static extern IntPtr GetTopWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
        public static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);

        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
        private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
        private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

        // This static method is required because Win32 does not support
        // GetWindowLongPtr directly
        public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
        {
            if (IntPtr.Size == 8)
                return GetWindowLongPtr64(hWnd, nIndex);
            else
                return GetWindowLongPtr32(hWnd, nIndex);
        }


        public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
        {
            if (IntPtr.Size == 8)
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            else
                return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
        }

        [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
        private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
        private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern nint GetForegroundWindow();

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(nint hWnd);


        //根据窗口来获取进程ID，
        public static int GetCurrentProcessID(IntPtr handle)
        {
            GetWindowThreadProcessId(handle, out int oo);
            return oo;
        }
        public struct WindowInfo
        {
            public IntPtr hWnd;
            public string szWindowName;
            public string szClassName;
            public int ProcessId { get; set; }

            public int Width { get; set; }

            public int Height { get; set; }

            public int X { get; set; }

            public int Y { get; set; }
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;                             //最左坐标
            public int Top;                             //最上坐标
            public int Right;                           //最右坐标
            public int Bottom;                        //最下坐标
        }


        public static (int width, int height, int x, int y) GetWindowSize(IntPtr hwnd)
        {
            RECT rc = new RECT();
            GetWindowRect(hwnd, ref rc);

            int width = rc.Right - rc.Left;                    //窗口的宽度
            int height = rc.Bottom - rc.Top;                   //窗口的高度
            int x = rc.Left;
            int y = rc.Top;


            return (width, height, x, y);
        }




        /*
         SetWindowLong(ChildWindowHandle, GWL_EXSTYLE, (GetWindowLong(ChildWindowHandle, GWL_EXSTYLE) | WS_EX_NOPARENTNOTIFY));
         */
        public enum GWL
        {
            GWL_WNDPROC = -4,
            GWL_HINSTANCE = -6,
            GWL_HWNDPARENT = -8,
            GWL_STYLE = -16,
            GWL_EXSTYLE = -20,
            GWL_USERDATA = -21,
            GWL_ID = -12
        }

        public static nint SetWindowStyle(IntPtr hwnd)
        {
            return SetWindowLong(hwnd, (int)GWL.GWL_EXSTYLE, GetWindowLong(hwnd, (int)GWL.GWL_EXSTYLE) | 0x00000004);
        }

        public static bool ReSetParent(IntPtr hWnd)
        {
            int row = SetParent(hWnd, GetDesktopWindow());
            MoveWindow(hWnd, 0, 0, 0, 0, true);
            return row > 0;
        }


        public static WindowInfo GetWindowInfo(nint hWnd)
        {
            WindowInfo wnd = new WindowInfo();
            StringBuilder sb = new StringBuilder(256);
            //get hwnd
            wnd.hWnd = hWnd;
            //get window name
            GetWindowTextW(hWnd, sb, sb.Capacity);
            wnd.szWindowName = sb.ToString();
            //get window class
            GetClassNameW(hWnd, sb, sb.Capacity);
            wnd.szClassName = sb.ToString();
            wnd.ProcessId = GetCurrentProcessID(hWnd);

            var size = GetWindowSize(hWnd);
            wnd.Width = size.width;
            wnd.Height = size.height;
            wnd.X = size.x;
            wnd.Y = size.y;

            return wnd;
        }



        public List<WindowInfo> GetAllDesktopWindows()
        {
            List<WindowInfo> wndList = new List<WindowInfo>();

            //enum all desktop windows
            EnumWindows(delegate (IntPtr hWnd, int lParam)
            {
                WindowInfo wnd = new WindowInfo();
                StringBuilder sb = new StringBuilder(256);
                //get hwnd
                wnd.hWnd = hWnd;
                //get window name
                GetWindowTextW(hWnd, sb, sb.Capacity);
                wnd.szWindowName = sb.ToString();
                //get window class
                GetClassNameW(hWnd, sb, sb.Capacity);
                wnd.szClassName = sb.ToString();
                wnd.ProcessId = GetCurrentProcessID(hWnd);

                var (width, height, x, y) = GetWindowSize(hWnd);
                wnd.Width = width;
                wnd.Height = height;
                wnd.X = x;
                wnd.Y = y;

                //add it into list
                wndList.Add(wnd);
                return true;
            }, 0);

            return wndList;
        }
        //获取窗体位置 最小化 最大化 隐藏 api
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);



    }

}

public struct WINDOWPLACEMENT
{
    public int length;
    public int flags;
    public int showCmd;
    public Point ptMinPosition;
    public Point ptMaxPosition;
    public Rectangle rcNormalPosition;
}
